package com.smart.community.region.service.impl;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.smart.community.commons.utils.StringUtils;
import com.smart.community.region.dto.RegionTreeVO;
import com.smart.community.region.entity.Region;
import com.smart.community.region.mapper.RegionMapper;
import com.smart.community.region.service.RegionCacheService;

import lombok.extern.slf4j.Slf4j;

/**
 * 区域缓存服务实现类
 * 
 * 功能说明：
 * 1. 为区域表的高频查询提供Redis缓存支持
 * 2. 实现缓存降级机制，确保系统稳定性
 * 3. 提供缓存清理和预热功能
 * 4. 严格按照《Java后端SpringBoot代码开发规范.md》实现
 * 5. 遵循《智慧社区微服务架构总览.md》的缓存设计规范
 * 
 * 缓存策略：
 * - 区域详情缓存：2小时过期
 * - 区域编码缓存：2小时过期
 * - 区域类型缓存：4小时过期
 * - 子区域缓存：2小时过期
 * - 区域路径缓存：4小时过期
 * - 区域树缓存：1小时过期
 * - 启用区域缓存：6小时过期
 * - 所有区域缓存：1小时过期
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 * @version 1.0.0
 */
@Slf4j
@Service
public class RegionCacheServiceImpl implements RegionCacheService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RegionMapper regionMapper;

    @Autowired
    private ObjectMapper objectMapper;

    // ==================== 缓存键前缀 ====================
    private static final String REGION_CACHE_PREFIX = "region:";
    private static final String REGION_DETAIL_CACHE_PREFIX = "region:detail:";
    private static final String REGION_CODE_CACHE_PREFIX = "region:code:";
    private static final String REGION_TYPE_CACHE_PREFIX = "region:type:";
    private static final String REGION_CHILDREN_CACHE_PREFIX = "region:children:";
    private static final String REGION_PATH_CACHE_PREFIX = "region:path:";
    private static final String REGION_TREE_CACHE_PREFIX = "region:tree:";
    private static final String REGION_ENABLED_CACHE_PREFIX = "region:enabled:";
    private static final String REGION_ALL_CACHE_PREFIX = "region:all:";

    // ==================== 缓存过期时间（秒） ====================
    private static final long REGION_DETAIL_CACHE_EXPIRE = 2 * 60 * 60; // 2小时
    private static final long REGION_CODE_CACHE_EXPIRE = 2 * 60 * 60; // 2小时
    private static final long REGION_TYPE_CACHE_EXPIRE = 4 * 60 * 60; // 4小时
    private static final long REGION_CHILDREN_CACHE_EXPIRE = 2 * 60 * 60; // 2小时
    private static final long REGION_PATH_CACHE_EXPIRE = 4 * 60 * 60; // 4小时
    private static final long REGION_TREE_CACHE_EXPIRE = 1 * 60 * 60; // 1小时
    private static final long REGION_ENABLED_CACHE_EXPIRE = 6 * 60 * 60; // 6小时
    private static final long REGION_ALL_CACHE_EXPIRE = 1 * 60 * 60; // 1小时

    // ==================== 区域详情缓存 ====================

    @Override
    public Region getRegionById(Long regionId) {
        log.debug("根据区域ID获取区域信息（带缓存），区域ID：{}", regionId);
        
        if (regionId == null) {
            log.warn("区域ID为空，返回null");
            return null;
        }
        
        String cacheKey = REGION_DETAIL_CACHE_PREFIX + regionId;
        
        try {
            // 1. 尝试从缓存获取
            Region cachedRegion = getFromCache(cacheKey, Region.class);
            if (cachedRegion != null) {
                log.debug("从缓存获取区域信息成功，区域ID：{}", regionId);
                return cachedRegion;
            }
            
            // 2. 缓存未命中，从数据库查询
            Region region = regionMapper.selectById(regionId);
            if (region != null) {
                // 3. 缓存查询结果
                setCache(cacheKey, region, REGION_DETAIL_CACHE_EXPIRE);
                log.debug("区域信息已缓存，区域ID：{}", regionId);
            }
            
            return region;
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询，区域ID：{}", regionId, e);
            return regionMapper.selectById(regionId);
        }
    }

    @Override
    public Region getRegionByCode(String regionCode) {
        log.debug("根据区域编码获取区域信息（带缓存），区域编码：{}", regionCode);
        
        if (StringUtils.isBlank(regionCode)) {
            log.warn("区域编码为空，返回null");
            return null;
        }
        
        String cacheKey = REGION_CODE_CACHE_PREFIX + regionCode;
        
        try {
            // 1. 尝试从缓存获取
            Region cachedRegion = getFromCache(cacheKey, Region.class);
            if (cachedRegion != null) {
                log.debug("从缓存获取区域信息成功，区域编码：{}", regionCode);
                return cachedRegion;
            }
            
            // 2. 缓存未命中，从数据库查询
            Region region = regionMapper.selectByRegionCode(regionCode);
            if (region != null) {
                // 3. 缓存查询结果
                setCache(cacheKey, region, REGION_CODE_CACHE_EXPIRE);
                log.debug("区域信息已缓存，区域编码：{}", regionCode);
            }
            
            return region;
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询，区域编码：{}", regionCode, e);
            return regionMapper.selectByRegionCode(regionCode);
        }
    }

    @Override
    public List<Region> getRegionsByType(Integer regionType) {
        log.debug("根据区域类型获取区域列表（带缓存），区域类型：{}", regionType);
        
        if (regionType == null) {
            log.warn("区域类型为空，返回空列表");
            return Collections.emptyList();
        }
        
        String cacheKey = REGION_TYPE_CACHE_PREFIX + regionType;
        
        try {
            // 1. 尝试从缓存获取
            List<Region> cachedRegions = getFromCache(cacheKey, new TypeReference<List<Region>>() {});
            if (cachedRegions != null) {
                log.debug("从缓存获取区域列表成功，区域类型：{}", regionType);
                return cachedRegions;
            }
            
            // 2. 缓存未命中，从数据库查询
            List<Region> regions = regionMapper.selectByRegionType(regionType);
            if (regions != null && !regions.isEmpty()) {
                // 3. 缓存查询结果
                setCache(cacheKey, regions, REGION_TYPE_CACHE_EXPIRE);
                log.debug("区域列表已缓存，区域类型：{}", regionType);
            }
            
            return regions != null ? regions : Collections.emptyList();
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询，区域类型：{}", regionType, e);
            List<Region> regions = regionMapper.selectByRegionType(regionType);
            return regions != null ? regions : Collections.emptyList();
        }
    }

    @Override
    public List<Region> getChildRegions(Long parentId) {
        log.debug("获取子区域列表（带缓存），父区域ID：{}", parentId);
        
        String cacheKey = REGION_CHILDREN_CACHE_PREFIX + (parentId != null ? parentId : "root");
        
        try {
            // 1. 尝试从缓存获取
            List<Region> cachedRegions = getFromCache(cacheKey, new TypeReference<List<Region>>() {});
            if (cachedRegions != null) {
                log.debug("从缓存获取子区域列表成功，父区域ID：{}", parentId);
                return cachedRegions;
            }
            
            // 2. 缓存未命中，从数据库查询
            List<Region> regions = regionMapper.selectChildren(parentId);
            if (regions != null && !regions.isEmpty()) {
                // 3. 缓存查询结果
                setCache(cacheKey, regions, REGION_CHILDREN_CACHE_EXPIRE);
                log.debug("子区域列表已缓存，父区域ID：{}", parentId);
            }
            
            return regions != null ? regions : Collections.emptyList();
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询，父区域ID：{}", parentId, e);
            List<Region> regions = regionMapper.selectChildren(parentId);
            return regions != null ? regions : Collections.emptyList();
        }
    }

    @Override
    public List<Region> getRegionPath(Long regionId) {
        log.debug("获取区域层级路径（带缓存），区域ID：{}", regionId);
        
        if (regionId == null) {
            log.warn("区域ID为空，返回空列表");
            return Collections.emptyList();
        }
        
        String cacheKey = REGION_PATH_CACHE_PREFIX + regionId;
        
        try {
            // 1. 尝试从缓存获取
            List<Region> cachedRegions = getFromCache(cacheKey, new TypeReference<List<Region>>() {});
            if (cachedRegions != null) {
                log.debug("从缓存获取区域路径成功，区域ID：{}", regionId);
                return cachedRegions;
            }
            
            // 2. 缓存未命中，从数据库查询
            List<Region> regions = regionMapper.selectRegionPath(regionId);
            if (regions != null && !regions.isEmpty()) {
                // 3. 缓存查询结果
                setCache(cacheKey, regions, REGION_PATH_CACHE_EXPIRE);
                log.debug("区域路径已缓存，区域ID：{}", regionId);
            }
            
            return regions != null ? regions : Collections.emptyList();
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询，区域ID：{}", regionId, e);
            List<Region> regions = regionMapper.selectRegionPath(regionId);
            return regions != null ? regions : Collections.emptyList();
        }
    }

    @Override
    public List<RegionTreeVO> getRegionTree(Long parentId) {
        log.debug("获取区域树形结构（带缓存），父区域ID：{}", parentId);
        
        String cacheKey = REGION_TREE_CACHE_PREFIX + (parentId != null ? parentId : "root");
        
        try {
            // 1. 尝试从缓存获取
            List<RegionTreeVO> cachedTree = getFromCache(cacheKey, new TypeReference<List<RegionTreeVO>>() {});
            if (cachedTree != null) {
                log.debug("从缓存获取区域树成功，父区域ID：{}", parentId);
                return cachedTree;
            }
            
            // 2. 缓存未命中，从数据库查询
            List<RegionTreeVO> tree = regionMapper.selectRegionTree(parentId);
            if (tree != null && !tree.isEmpty()) {
                // 3. 缓存查询结果
                setCache(cacheKey, tree, REGION_TREE_CACHE_EXPIRE);
                log.debug("区域树已缓存，父区域ID：{}", parentId);
            }
            
            return tree != null ? tree : Collections.emptyList();
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询，父区域ID：{}", parentId, e);
            List<RegionTreeVO> tree = regionMapper.selectRegionTree(parentId);
            return tree != null ? tree : Collections.emptyList();
        }
    }

    @Override
    public List<Region> getEnabledRegions() {
        log.debug("获取所有启用的区域列表（带缓存）");
        
        String cacheKey = REGION_ENABLED_CACHE_PREFIX + "all";
        
        try {
            // 1. 尝试从缓存获取
            List<Region> cachedRegions = getFromCache(cacheKey, new TypeReference<List<Region>>() {});
            if (cachedRegions != null) {
                log.debug("从缓存获取启用区域列表成功");
                return cachedRegions;
            }
            
            // 2. 缓存未命中，从数据库查询
            List<Region> regions = regionMapper.selectEnabledRegions();
            if (regions != null && !regions.isEmpty()) {
                // 3. 缓存查询结果
                setCache(cacheKey, regions, REGION_ENABLED_CACHE_EXPIRE);
                log.debug("启用区域列表已缓存");
            }
            
            return regions != null ? regions : Collections.emptyList();
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询", e);
            List<Region> regions = regionMapper.selectEnabledRegions();
            return regions != null ? regions : Collections.emptyList();
        }
    }

    @Override
    public List<Region> getAllRegions() {
        log.debug("获取所有区域列表（带缓存）");
        
        String cacheKey = REGION_ALL_CACHE_PREFIX + "all";
        
        try {
            // 1. 尝试从缓存获取
            List<Region> cachedRegions = getFromCache(cacheKey, new TypeReference<List<Region>>() {});
            if (cachedRegions != null) {
                log.debug("从缓存获取所有区域列表成功");
                return cachedRegions;
            }
            
            // 2. 缓存未命中，从数据库查询
            List<Region> regions = regionMapper.selectList(null);
            if (regions != null && !regions.isEmpty()) {
                // 3. 缓存查询结果
                setCache(cacheKey, regions, REGION_ALL_CACHE_EXPIRE);
                log.debug("所有区域列表已缓存");
            }
            
            return regions != null ? regions : Collections.emptyList();
            
        } catch (Exception e) {
            log.warn("缓存操作失败，直接从数据库查询", e);
            List<Region> regions = regionMapper.selectList(null);
            return regions != null ? regions : Collections.emptyList();
        }
    }

    // ==================== 缓存管理 ====================

    @Override
    public void clearRegionCache(Long regionId) {
        if (regionId == null) {
            log.warn("区域ID为空，跳过缓存清理");
            return;
        }
        
        try {
            String[] cacheKeys = {
                REGION_DETAIL_CACHE_PREFIX + regionId,
                REGION_PATH_CACHE_PREFIX + regionId,
                REGION_CHILDREN_CACHE_PREFIX + regionId,
                REGION_TREE_CACHE_PREFIX + regionId,
                REGION_ENABLED_CACHE_PREFIX + "all",
                REGION_ALL_CACHE_PREFIX + "all"
            };
            
            for (String cacheKey : cacheKeys) {
                redisTemplate.delete(cacheKey);
            }
            
            log.debug("清除区域缓存成功，区域ID：{}", regionId);
        } catch (Exception e) {
            log.warn("清除区域缓存失败，区域ID：{}", regionId, e);
        }
    }

    @Override
    public void clearRegionCodeCache(String regionCode) {
        if (StringUtils.isBlank(regionCode)) {
            log.warn("区域编码为空，跳过缓存清理");
            return;
        }
        
        try {
            String cacheKey = REGION_CODE_CACHE_PREFIX + regionCode;
            redisTemplate.delete(cacheKey);
            log.debug("清除区域编码缓存成功，区域编码：{}", regionCode);
        } catch (Exception e) {
            log.warn("清除区域编码缓存失败，区域编码：{}", regionCode, e);
        }
    }

    @Override
    public void clearRegionTypeCache(Integer regionType) {
        if (regionType == null) {
            log.warn("区域类型为空，跳过缓存清理");
            return;
        }
        
        try {
            String cacheKey = REGION_TYPE_CACHE_PREFIX + regionType;
            redisTemplate.delete(cacheKey);
            log.debug("清除区域类型缓存成功，区域类型：{}", regionType);
        } catch (Exception e) {
            log.warn("清除区域类型缓存失败，区域类型：{}", regionType, e);
        }
    }

    @Override
    public void clearAllRegionCache() {
        try {
            log.info("开始清除所有区域缓存");
            
            // 清除所有区域相关的缓存
            String[] cachePatterns = {
                REGION_CACHE_PREFIX + "*"
            };
            
            for (String pattern : cachePatterns) {
                Set<String> keys = redisTemplate.keys(pattern);
                if (keys != null && !keys.isEmpty()) {
                    redisTemplate.delete(keys);
                    log.debug("清除缓存模式：{}，删除键数量：{}", pattern, keys.size());
                }
            }
            
            log.info("清除所有区域缓存完成");
        } catch (Exception e) {
            log.error("清除所有区域缓存失败", e);
        }
    }

    @Override
    public void warmUpRegionCache(List<Long> regionIds) {
        if (regionIds == null || regionIds.isEmpty()) {
            log.warn("区域ID列表为空，跳过缓存预热");
            return;
        }
        
        log.info("开始预热区域缓存，区域ID数量：{}", regionIds.size());
        
        int successCount = 0;
        int failCount = 0;
        
        for (Long regionId : regionIds) {
            try {
                // 预热区域详情缓存
                Region region = regionMapper.selectById(regionId);
                if (region != null) {
                    String cacheKey = REGION_DETAIL_CACHE_PREFIX + regionId;
                    setCache(cacheKey, region, REGION_DETAIL_CACHE_EXPIRE);
                    successCount++;
                    log.debug("预热区域详情缓存成功，区域ID：{}", regionId);
                } else {
                    log.warn("区域不存在，跳过预热，区域ID：{}", regionId);
                }
            } catch (Exception e) {
                failCount++;
                log.warn("预热区域缓存失败，区域ID：{}", regionId, e);
            }
        }
        
        log.info("区域缓存预热完成，成功：{}，失败：{}", successCount, failCount);
    }

    @Override
    public void warmUpRegionTypeCache(List<Integer> regionTypes) {
        if (regionTypes == null || regionTypes.isEmpty()) {
            log.warn("区域类型列表为空，跳过缓存预热");
            return;
        }
        
        log.info("开始预热区域类型缓存，区域类型数量：{}", regionTypes.size());
        
        int successCount = 0;
        int failCount = 0;
        
        for (Integer regionType : regionTypes) {
            try {
                // 预热区域类型缓存
                List<Region> regions = regionMapper.selectByRegionType(regionType);
                if (regions != null && !regions.isEmpty()) {
                    String cacheKey = REGION_TYPE_CACHE_PREFIX + regionType;
                    setCache(cacheKey, regions, REGION_TYPE_CACHE_EXPIRE);
                    successCount++;
                    log.debug("预热区域类型缓存成功，区域类型：{}", regionType);
                } else {
                    log.warn("区域类型无数据，跳过预热，区域类型：{}", regionType);
                }
            } catch (Exception e) {
                failCount++;
                log.warn("预热区域类型缓存失败，区域类型：{}", regionType, e);
            }
        }
        
        log.info("区域类型缓存预热完成，成功：{}，失败：{}", successCount, failCount);
    }

    @Override
    public Object getCacheStatistics() {
        try {
            log.debug("获取缓存统计信息");
            
            // 获取缓存统计信息
            Map<String, Object> statistics = new HashMap<>();
            
            // 缓存前缀信息
            Map<String, Object> cachePrefixes = new HashMap<>();
            cachePrefixes.put("prefixes", Arrays.asList(
                REGION_DETAIL_CACHE_PREFIX,
                REGION_CODE_CACHE_PREFIX,
                REGION_TYPE_CACHE_PREFIX,
                REGION_CHILDREN_CACHE_PREFIX,
                REGION_PATH_CACHE_PREFIX,
                REGION_TREE_CACHE_PREFIX,
                REGION_ENABLED_CACHE_PREFIX,
                REGION_ALL_CACHE_PREFIX
            ));
            
            // 过期时间信息
            Map<String, Object> expireTimes = new HashMap<>();
            expireTimes.put("regionDetail", REGION_DETAIL_CACHE_EXPIRE);
            expireTimes.put("regionCode", REGION_CODE_CACHE_EXPIRE);
            expireTimes.put("regionType", REGION_TYPE_CACHE_EXPIRE);
            expireTimes.put("regionChildren", REGION_CHILDREN_CACHE_EXPIRE);
            expireTimes.put("regionPath", REGION_PATH_CACHE_EXPIRE);
            expireTimes.put("regionTree", REGION_TREE_CACHE_EXPIRE);
            expireTimes.put("regionEnabled", REGION_ENABLED_CACHE_EXPIRE);
            expireTimes.put("regionAll", REGION_ALL_CACHE_EXPIRE);
            
            // 缓存键数量统计
            Map<String, Object> keyCounts = new HashMap<>();
            for (String prefix : Arrays.asList(
                REGION_DETAIL_CACHE_PREFIX,
                REGION_CODE_CACHE_PREFIX,
                REGION_TYPE_CACHE_PREFIX,
                REGION_CHILDREN_CACHE_PREFIX,
                REGION_PATH_CACHE_PREFIX,
                REGION_TREE_CACHE_PREFIX,
                REGION_ENABLED_CACHE_PREFIX,
                REGION_ALL_CACHE_PREFIX
            )) {
                Set<String> keys = redisTemplate.keys(prefix + "*");
                keyCounts.put(prefix.replace(":", "_"), keys != null ? keys.size() : 0);
            }
            
            statistics.put("cachePrefixes", cachePrefixes);
            statistics.put("expireTimes", expireTimes);
            statistics.put("keyCounts", keyCounts);
            statistics.put("timestamp", System.currentTimeMillis());
            
            log.debug("获取缓存统计信息成功");
            return statistics;
            
        } catch (Exception e) {
            log.error("获取缓存统计信息失败", e);
            Map<String, String> errorMap = new HashMap<>();
            errorMap.put("error", "获取缓存统计信息失败：" + e.getMessage());
            errorMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
            return errorMap;
        }
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 从缓存中获取对象
     * 
     * @param cacheKey 缓存键
     * @param clazz 目标类型
     * @param <T> 泛型类型
     * @return 缓存对象，如果不存在返回null
     */
    private <T> T getFromCache(String cacheKey, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForValue().get(cacheKey);
            if (value != null) {
                return objectMapper.convertValue(value, clazz);
            }
            return null;
        } catch (Exception e) {
            log.warn("从缓存获取对象失败，缓存键：{}", cacheKey, e);
            return null;
        }
    }

    /**
     * 从缓存中获取对象（支持复杂类型）
     * 
     * @param cacheKey 缓存键
     * @param typeReference 类型引用
     * @param <T> 泛型类型
     * @return 缓存对象，如果不存在返回null
     */
    private <T> T getFromCache(String cacheKey, TypeReference<T> typeReference) {
        try {
            Object value = redisTemplate.opsForValue().get(cacheKey);
            if (value != null) {
                return objectMapper.convertValue(value, typeReference);
            }
            return null;
        } catch (Exception e) {
            log.warn("从缓存获取对象失败，缓存键：{}", cacheKey, e);
            return null;
        }
    }

    /**
     * 设置缓存
     * 
     * @param cacheKey 缓存键
     * @param value 缓存值
     * @param expireTime 过期时间（秒）
     */
    private void setCache(String cacheKey, Object value, long expireTime) {
        try {
            redisTemplate.opsForValue().set(cacheKey, value, expireTime, TimeUnit.SECONDS);
            log.debug("设置缓存成功，缓存键：{}，过期时间：{}秒", cacheKey, expireTime);
        } catch (Exception e) {
            log.warn("设置缓存失败，缓存键：{}", cacheKey, e);
        }
    }
}
